home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / filesyst / ext2 / quotache.new / quotache / quotacheck.c < prev    next >
C/C++ Source or Header  |  1995-02-19  |  20KB  |  725 lines

  1. /*
  2.  * QUOTA    An implementation of the diskquota system for the LINUX operating
  3.  *          system. QUOTA is implemented using the BSD systemcall interface
  4.  *          as the means of communication with the user level. Should work for
  5.  *          all filesystems because of integration into the VFS layer of the
  6.  *          operating system. This is based on the Melbourne quota system wich
  7.  *          uses both user and group quota files.
  8.  * 
  9.  *          Program to check disk quotas.
  10.  * 
  11.  * Authors:
  12.  *          Disk reading routines: Edvard Tuinder <ed@ow.org>
  13.  *          Quota storing routines: Marco van Wieringen <mvw@mcs.ow.org>
  14.  *
  15.  *          This program is free software; you can redistribute it and/or
  16.  *          modify it under the terms of the GNU General Public License as
  17.  *          published by the Free Software Foundation; either version 2 of
  18.  *          the License, or (at your option) any later version.
  19.  */
  20.  
  21. /* NOTE: This is a PRE-ALPHA version !
  22.  
  23.    This version of quotacheck is based on the `hints' of Remy Card and has
  24.    *NOT* been fully tested. It *SHOULD* not be able to destroy any data,
  25.    but *ANYTHING* may happen.
  26.  
  27.    Comments please to ed@ow.org.
  28.  */
  29.  
  30. #include <sys/types.h>
  31. #include <sys/param.h>
  32. #include <dirent.h>
  33. #include <sys/stat.h>
  34. #include <stdio.h>
  35. #include <linux/quota.h>
  36. #include <stdarg.h>
  37. #include <sys/file.h>
  38. #include <mntent.h>
  39. #include <getopt.h>
  40. #include <limits.h>
  41. #include <unistd.h>
  42. #include <stdlib.h>
  43. #include <e2fsck.h>
  44.  
  45. #define DEF_BLOCKSIZE 1024
  46. #define NODQUOT (struct dquot *)NULL
  47.  
  48. #ifndef lint
  49. static char RCS_checkquota[] = "$Id: quotacheck.c,v 2.6 1995/02/18 19:57:20 ed Exp root $";
  50. #endif
  51.  
  52. struct dquot {
  53.    int          dq_id;  /* id this applies to (uid, gid) */
  54.    struct dqblk dq_dqb; /* diskquota for id */
  55.    struct dquot *next;  /* pointer to next id */
  56. };
  57.  
  58. struct dlinks {
  59.    ino_t ino;
  60.    size_t size;
  61.    size_t blksize;
  62.    u_long id;
  63.    struct dlinks *next;
  64. };
  65.  
  66. struct dirs {
  67.    char *dir_name;
  68.    struct dirs *next;
  69. };
  70.  
  71. void add_to_quota(struct stat *, int);
  72. void dump_to_file(char *, char *, int);
  73. void store_dlinks(struct stat *, int);
  74. void remove_list(void);
  75. void scan_dir(char *);
  76. void scan_fs(char *);
  77. void add_to_quota_ext2(int, long, int);
  78. void abort_now(const char *, const char *, ...);
  79. void add_dlinks(u_long *, u_long *, int, int);
  80.  
  81. static char bits[] = "|/-\\";
  82. #define BITS_SIZE 4 /* sizeof(bits) == 5 */
  83.  
  84. dev_t cur_dev;
  85. char dflag = 0, vflag = 0;
  86. char check_usr, check_grp;
  87. long files_done, dirs_done;
  88. u_long highestid[MAXQUOTAS];
  89. char *quotatypes[] = INITQFNAMES;
  90. char log_buf[16384]; /* for dflag stderr buffering */
  91. #ifdef DEBUG_MALLOC
  92. static size_t malloc_mem = 0;
  93. static size_t free_mem = 0;
  94. #endif
  95.  
  96. struct dquot *dquot_list[MAXQUOTAS] = {NODQUOT, NODQUOT};
  97. struct dquot *mru_dquot[MAXQUOTAS] = {NODQUOT, NODQUOT};
  98. struct dlinks *stored_links[MAXQUOTAS] = {(struct dlinks *)NULL, (struct dlinks *)NULL};
  99.  
  100. /*
  101.  * This simple algorithm calculates the size of a file in blocks.
  102.  * It is not perfect but works most of the time.
  103.  */
  104. static inline size_t isize_to_blocks(size_t isize, size_t blksize)
  105. {
  106.    u_long blocks;
  107.    u_long indirect;
  108.  
  109.    if (!blksize)
  110.       blksize = DEF_BLOCKSIZE;
  111.  
  112.    blocks = (isize / blksize) + ((isize % blksize) ? 1 : 0);
  113.    if (blocks > 10) {
  114.       indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */
  115.       if (blocks > (10 + 256)) {
  116.          indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */
  117.          if (blocks > (10 + 256 + (256 << 8)))
  118.             indirect++; /* triple indirect blocks */
  119.       }
  120.       blocks += indirect;
  121.    }
  122.    return blocks;
  123. }
  124.  
  125. /*
  126.  * Ok check each memory allocation.
  127.  */
  128. void *xmalloc(size_t size)
  129. {
  130.    void *ptr;
  131.  
  132. #ifdef DEBUG_MALLOC
  133.    malloc_mem += size;
  134. #endif
  135.    ptr = malloc(size);
  136.    if (ptr == (void *)NULL)
  137.       abort_now("xmalloc", "Virtual memory exhausted\n");
  138.    memset(ptr, 0, size);
  139.    return(ptr);
  140. }
  141.  
  142. /*
  143.  * Do a lookup of a type of quota for a specific id. Use short cut with
  144.  * most recently used dquot struct pointer.
  145.  */
  146. static inline struct dquot *lookup_dquot(int id, int type)
  147. {
  148.    register struct dquot *lptr = NODQUOT;
  149.  
  150.    /*
  151.     * First fast lookup when same as used before.
  152.     */
  153.    if (mru_dquot[type] != NODQUOT && mru_dquot[type]->dq_id == id)
  154.       return (mru_dquot[type]);
  155.  
  156.    for (lptr = dquot_list[type]; lptr != NODQUOT; lptr = lptr->next)
  157.       if (lptr->dq_id == id) {
  158.          mru_dquot[type] = lptr;
  159.          return (lptr);
  160.       }
  161.    return(NODQUOT);
  162. }
  163.  
  164. /*
  165.  * Add a new dquot for a new id to the list.
  166.  */
  167. static inline struct dquot *add_dquot(int id, int type)
  168. {
  169.    register struct dquot *lptr;
  170.  
  171.    if (dflag)
  172.       fprintf(stderr, "Adding dquot structure type %s for %d\n",
  173.           quotatypes[type], id);
  174.  
  175.    lptr = (struct dquot *)xmalloc(sizeof(struct dquot));
  176.  
  177.    lptr->dq_id = id;
  178.    lptr->next = dquot_list[type];
  179.    dquot_list[type] = lptr;
  180.    lptr->dq_btime = lptr->dq_itime = (time_t) 0;
  181.  
  182.    if (id > highestid[type])
  183.       highestid[type] = id;
  184.  
  185.    return(lptr);
  186. }
  187.  
  188. /*
  189.  * Check the programs arguments for a specific target.
  190.  */
  191. int oneof(char *target, char *list[], int cnt)
  192. {
  193.    register int i;
  194.  
  195.    for (i = 0; i < cnt; i++)
  196.       if (strcmp(target, list[i]) == 0)
  197.          return (i);
  198.    return(-1);
  199. }
  200.  
  201. /*
  202.  * Show a blitting cursor as means of visual progress indicator.
  203.  */
  204. static void blit()
  205. {
  206.    static short bitc = 0;
  207.  
  208.    putc(bits[bitc], stdout);
  209.    putc('\b', stdout);
  210.    bitc++;
  211.    bitc %= BITS_SIZE;
  212. }
  213.  
  214. void usage()
  215. {
  216.    fputs("Usage:\n\tquotacheck [-g] [-u] [-vd] -a\n", stderr);
  217.    fputs("\tquotacheck [-g] [-u] [-vd] filesys ...\n", stderr);
  218.    exit(1);
  219. }
  220.  
  221. int main(int argc, char **argv)
  222. {
  223.    FILE *fp;
  224.    int cnt, ch;
  225.    struct stat st;
  226.    char aflag = 0, gflag = 0, uflag = 0;
  227.    long argnum, done;
  228.    char *usr_qfnp, *grp_qfnp;
  229.    register struct mntent *mnt;
  230.  
  231.    while ((ch = getopt(argc, argv, "avugd")) != EOF) {
  232.       switch (ch) {
  233.          case 'a':
  234.             aflag++;
  235.             break;
  236.          case 'g':
  237.             gflag++;
  238.             break;
  239.          case 'u':
  240.             uflag++;
  241.             break;
  242.          case 'd':
  243.             dflag++;
  244.         setbuf(stderr, log_buf);
  245.         break;
  246.          case 'v':
  247.             vflag++;
  248.         setbuf(stdout, (char *)NULL);
  249.             break;
  250.          default:
  251.             usage();
  252.       }
  253.    }
  254.    argc -= optind;
  255.    argv += optind;
  256.  
  257.    if (vflag && dflag)
  258.      vflag = 0;
  259.  
  260.    if (!uflag && !gflag)
  261.       uflag++;
  262.  
  263.    if (!aflag && argc == 0)
  264.       usage();
  265.  
  266.    fp = setmntent(MNTTAB, "r");
  267.    while ((mnt = getmntent(fp)) != (struct mntent *) NULL) {
  268.       check_usr = check_grp = 0;
  269.       if (argc && ((argnum = oneof(mnt->mnt_dir, argv, argc)) >= 0) ||
  270.                   ((argnum = oneof(mnt->mnt_fsname, argv, argc)) >= 0)) {
  271.           done |= 1 << argnum;
  272.       } else
  273.          if (!aflag || hasmntopt(mnt, MNTOPT_NOAUTO) ||
  274.                        hasmntopt(mnt, MNTOPT_NOQUOTA))
  275.             continue;
  276.  
  277.       if (gflag && hasquota(mnt, GRPQUOTA, &grp_qfnp))
  278.          check_grp++;
  279.       if (uflag && hasquota(mnt, USRQUOTA, &usr_qfnp))
  280.          check_usr++;
  281.       if (check_usr || check_grp) {
  282.      if ((lstat(mnt->mnt_dir, &st)) == -1) {
  283.        fprintf(stderr, "%s: not found\n", mnt->mnt_dir);
  284.        perror("lstat");
  285.            continue;
  286.      }
  287.  
  288.      if (vflag)
  289.        fprintf(stdout,"Scanning %s [%s] ", mnt->mnt_fsname, mnt->mnt_dir);
  290.  
  291.      if (S_ISDIR(st.st_mode)) {
  292.            cur_dev = st.st_dev;
  293.            files_done = dirs_done = 0;
  294.            if (check_usr)
  295.           add_to_quota(&st, USRQUOTA);
  296.            if (check_grp)
  297.           add_to_quota(&st, GRPQUOTA);
  298.        if (strcmp(mnt->mnt_type, MNTTYPE_EXT2)) {
  299.          scan_dir(mnt->mnt_dir);
  300.        } else {
  301.          scan_fs(mnt->mnt_fsname);
  302.        }
  303.        dirs_done++;
  304.        if (vflag)
  305.           fputs("done\n", stderr);
  306.            if (vflag || dflag)
  307.               fprintf(stderr, "Checked %d directories and %d files\n",
  308.                       dirs_done, files_done);
  309.      } else {
  310.        fprintf(stderr, "%s: not a directory\n", mnt->mnt_dir);
  311.        exit(0);
  312.      }
  313.  
  314.          if (check_usr)
  315.             dump_to_file(mnt->mnt_fsname, usr_qfnp, USRQUOTA);
  316.          if (check_grp)
  317.             dump_to_file(mnt->mnt_fsname, grp_qfnp, GRPQUOTA);
  318.          remove_list();
  319.       }
  320.    }
  321.    endmntent(fp);
  322.  
  323.    for (cnt = 0; cnt < argc; cnt++)
  324.       if ((done & (1 << cnt)) == 0)
  325.          fprintf(stderr, "%s not found in fstab\n", argv[cnt]);
  326.  
  327. #ifdef DEBUG_MALLOC
  328.    fprintf (stderr, "Allocated %d bytes memory\nFree'd %d bytes\nLost %d bytes\n", malloc_mem,
  329.     free_mem, malloc_mem - free_mem);
  330. #endif
  331.    exit(0);
  332. }
  333.  
  334. /* 
  335.   Scan a certain device by walking thru its inode bitmap. This applies to ext2
  336.   *ONLY*.
  337.  
  338.   Please note that this is a preliminary implementation. It is not final,
  339.   perfect or whatever. It works. Nuff said.
  340.  
  341.   It needs to be modified though!
  342.  */
  343. void scan_fs(char *device)
  344. {
  345.   ext2_filsys    fs;
  346.   errcode_t    error;
  347.   int inode_buffer_blocks = 0;
  348.   ino_t            ino;
  349.   struct ext2_inode    inode;
  350.   ext2_inode_scan        scan;
  351.   ext2fs_inode_bitmap    inode_used_map;
  352.   ext2fs_inode_bitmap    inode_dir_map;
  353.  
  354.   error = ext2fs_open(device, 0, 0, 0, unix_io_manager, &fs);
  355.   if (error) {
  356.     fprintf(stderr, "quotacheck: error while opening %s\n", device);
  357.     exit (0);
  358.   }
  359.   error = ext2fs_allocate_inode_bitmap(fs, "in-use inode map", &inode_used_map);
  360.   if (error) {
  361.     fprintf (stderr, "quotacheck: error while allocating inode file bitmap\n");
  362.     exit (0);
  363.   }
  364.   error = ext2fs_allocate_inode_bitmap(fs, "directory inode map", &inode_dir_map);
  365.   if (error) {
  366.     fprintf (stderr, "quotacheck: error while allocating inode directory bitmap\n");
  367.     exit (0);
  368.   }
  369.   error = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan);
  370.   if (error) {
  371.     fprintf(stderr, "quotacheck: error while opening inode scan\n");
  372.     exit (0);
  373.   }
  374.   error = ext2fs_get_next_inode(scan, &ino, &inode);
  375.   if (error) {
  376.     fprintf(stderr, "quotacheck: error while starting inode scan\n");
  377.     exit (0);
  378.   }
  379.   while (ino) {
  380.     if (inode.i_links_count) {
  381.       if (dflag)
  382.     printf ("%ld\n", ino);
  383.       if (vflag)
  384.     blit();
  385.       if (check_usr)
  386.     add_to_quota_ext2(inode.i_uid, inode.i_blocks, USRQUOTA);
  387.       if (check_grp)
  388.     add_to_quota_ext2(inode.i_gid, inode.i_blocks, GRPQUOTA);
  389.       if (S_ISDIR(inode.i_mode))
  390.     dirs_done++;
  391.       else
  392.     files_done++;
  393.     }
  394.     error = ext2fs_get_next_inode(scan, &ino, &inode);
  395.     if (error) {
  396.       fprintf (stderr, "Something weird while scanning\n");
  397.       exit (0);
  398.     }
  399.   }
  400. }
  401.  
  402. /*
  403.  * Scan a directory with the readdir systemcall. Stat the files and add the sizes
  404.  * of the files to the appropriate quotas. When we find a dir we recursivly call
  405.  * ourself to scan that dir.
  406.  */
  407. void scan_dir(char *pathname)
  408. {
  409.    struct dirs *dir_stack = {(struct dirs *)NULL};
  410.    struct dirs *new_dir;
  411.    struct dirent *de;
  412.    struct stat st;
  413.    DIR *dp;
  414.  
  415.    if ((dp = opendir(pathname)) == (DIR *)NULL)
  416.       abort_now("opendir", "\n%s\n", pathname);
  417.  
  418.    chdir(pathname);
  419.    while ((de = readdir(dp)) != (struct dirent *)NULL) {
  420.       if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
  421.          continue;
  422.       if (vflag)
  423.          blit();
  424.  
  425.       if ((lstat(de->d_name, &st)) == -1) {
  426.      fprintf(stderr, "Hmm, file `%s/%s' not found\n", pathname, de->d_name);
  427.          fputs("Guess you'd better run fsck first !\nexiting...\n", stderr);
  428.          perror("lstat");
  429.          exit(1);
  430.       }
  431.  
  432.       if (check_usr)
  433.      add_to_quota(&st, USRQUOTA);
  434.       if (check_grp)
  435.      add_to_quota(&st, GRPQUOTA);
  436.  
  437.       if (S_ISDIR(st.st_mode)) {
  438.          if (st.st_dev != cur_dev)
  439.             continue;
  440.          /*
  441.           * Add this to the directory stack and check this later on.
  442.           */
  443.      if (dflag)
  444.         fprintf(stderr, "pushd %s/%s\n", pathname, de->d_name);
  445.          new_dir = xmalloc(sizeof(struct dirs));
  446.          new_dir->dir_name = xmalloc(strlen(pathname) + strlen(de->d_name) + 2);
  447.          sprintf(new_dir->dir_name, "%s/%s", pathname, de->d_name);
  448.          new_dir->next = dir_stack;
  449.          dir_stack = new_dir;
  450.       } else {
  451.      if (dflag)
  452.         fprintf(stderr, "\tAdding %s size %d ino %d links %d\n", de->d_name,
  453.             st.st_size, st.st_ino, st.st_nlink);
  454.          files_done++;
  455.       }
  456.    }
  457.    closedir(dp);
  458.  
  459.    /*
  460.     * Traverse the directory stack, and check it.
  461.     */
  462.    if (dflag)
  463.       fputs("Scanning stored directories from directory stack\n", stderr);
  464.    while (dir_stack != (struct dirs *)NULL) {
  465.       new_dir = dir_stack;
  466.       dir_stack = dir_stack->next;
  467.       if (dflag)
  468.          fprintf(stderr, "popd %s\nEntering directory %s\n",
  469.                  new_dir->dir_name, new_dir->dir_name);
  470.       scan_dir(new_dir->dir_name);
  471.       dirs_done++;
  472. #ifdef DEBUG_MALLOC
  473.       free_mem += sizeof(struct dirs) + strlen(new_dir->dir_name) + 1;
  474. #endif
  475.       free(new_dir->dir_name);
  476.       free(new_dir);
  477.    }
  478.    if (dflag)
  479.       fprintf(stderr, "Leaving %s\n", pathname);
  480. }
  481.     
  482. /*
  483.  * Store a hardlinked file for later. Add the end we add this to a users
  484.  * quota because we don't wanna count it more then ones.
  485.  */
  486. void store_dlinks(struct stat *st, int type)
  487. {
  488.    struct dlinks *lptr;
  489.  
  490.    if (dflag)
  491.       fprintf(stderr, "Adding hardlink for ino %d\n", st->st_ino);
  492.  
  493.    for (lptr = stored_links[type]; lptr != (struct dlinks *)NULL; lptr = lptr->next)
  494.       if (lptr->ino == st->st_ino)
  495.          return;
  496.  
  497.    lptr = (struct dlinks *)xmalloc(sizeof(struct dlinks));
  498.  
  499.    if (type == USRQUOTA)
  500.      lptr->id = st->st_uid;
  501.    else 
  502.      lptr->id = st->st_gid;
  503.  
  504.    lptr->ino = st->st_ino;
  505.    lptr->size = st->st_size;
  506.    lptr->blksize = st->st_blksize;
  507.  
  508.    lptr->next = stored_links[type];
  509.    stored_links[type] = lptr;
  510. }
  511.  
  512.  
  513. /*
  514.  * Add a number of blocks and inodes to a quota.
  515.  */
  516. void add_to_quota(struct stat *st, int type)
  517. {
  518.    int wanted;
  519.    struct dquot *lptr;
  520.  
  521.    switch(type)
  522.    {
  523.       case USRQUOTA:
  524.          wanted = st->st_uid;
  525.          break;
  526.       case GRPQUOTA:
  527.          wanted = st->st_gid;
  528.          break;
  529.       default:
  530.          return;
  531.    }
  532.  
  533.    if ((lptr = lookup_dquot(wanted, type)) == NODQUOT)
  534.       if ((lptr = add_dquot(wanted, type)) == NODQUOT)
  535.      abort_now("add_to_quota", "Can't add dquot structure type %s for uid %d\n",
  536.            quotatypes[type], wanted);
  537.  
  538.    /*
  539.     * A dir is a special case, we count it for 1 inode and 1 block.
  540.     */
  541.    if (S_ISDIR(st->st_mode)) {
  542.       lptr->dq_curinodes++;
  543.       lptr->dq_curblocks++;
  544.    } else {
  545.       /*
  546.        * A symlink is always counted as 1 inode and 1 block even if the 
  547.        * filesystem is smart and stuffs it into the inode. Be fair to other
  548.        * users that have there files on other filesystems that aren't that smart
  549.        * or have symlinks that don't go into the inode (e.g. to long).
  550.        */
  551.       if (S_ISLNK(st->st_mode)) {
  552.          lptr->dq_curinodes++;
  553.          lptr->dq_curblocks++;
  554.       } else {
  555.          if (st->st_nlink != 1) {
  556.             store_dlinks(st, type);
  557.             return;
  558.          }
  559.          lptr->dq_curinodes++;
  560.          if (st->st_size)
  561.             lptr->dq_curblocks += isize_to_blocks(st->st_size, st->st_blksize);
  562.       }
  563.    }
  564. }
  565.  
  566. void abort_now(const char *perror_mes, const char *fmt, ...)
  567. {
  568.    va_list args;
  569.  
  570.    va_start(args, fmt);
  571.    vfprintf(stderr, fmt, args);
  572.    va_end(args);
  573.  
  574.    fflush(stderr);
  575.    perror(perror_mes);
  576.    exit(-1);
  577. }
  578.  
  579. void add_dlinks(u_long * inodes, u_long * blocks, int id, int type)
  580. {
  581.    struct dlinks  *lptr;
  582.  
  583.    if (dflag)
  584.       fprintf(stderr, "Adding blocks from hardlinks for %s %d\n",
  585.               quotatypes[type], id);
  586.  
  587.    for (lptr = stored_links[type]; lptr != (struct dlinks *)NULL; lptr = lptr->next) {
  588.       if (lptr->id == id) {
  589.          (*inodes)++;
  590.          if (lptr->size)
  591.             *blocks += isize_to_blocks(lptr->size, lptr->blksize);
  592.          files_done++;
  593.       }
  594.    }
  595. }
  596.  
  597. /*
  598.  * Clean up all list from a previous run.
  599.  */
  600. void remove_list()
  601. {
  602.    int cnt;
  603.    struct dquot *dquot, *dquot_free;
  604.    struct dlinks *dlink, *dlink_free;
  605.  
  606.    for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
  607.       if (dquot_list[cnt] != NODQUOT) {
  608.          dquot = dquot_list[cnt];
  609.          while (dquot != NODQUOT) {
  610.             dquot_free = dquot;
  611.             dquot = dquot->next;
  612. #ifdef DEBUG_MALLOC
  613.         free_mem += sizeof(struct dquot);
  614. #endif
  615.             free(dquot_free);
  616.          }
  617.          mru_dquot[cnt] = NODQUOT;
  618.       }
  619.       dquot_list[cnt] = NODQUOT;
  620.       if (stored_links[cnt] != (struct dlinks *)NULL) {
  621.          dlink = stored_links[cnt];
  622.          while (dlink != (struct dlinks *)NULL) {
  623.             dlink_free = dlink;
  624.             dlink = dlink->next;
  625. #ifdef DEBUG_MALLOC
  626.         free_mem += sizeof(struct dlinks);
  627. #endif
  628.             free(dlink_free);
  629.          }
  630.       }
  631.       stored_links[cnt] = (struct dlinks *)NULL;
  632.    }
  633. }
  634.  
  635. /*
  636.  * Dump the quota info that we have in memory now to the appropriate
  637.  * quota file. We lock it during the time we update it.
  638.  */
  639. void dump_to_file(char *fsname, char *quotafile, int type)
  640. {
  641.    struct dqblk dq_dqb;
  642.    struct dquot *dquot;
  643.    int quota_enabled = 0, max_id;
  644.    int fd, id = 0;
  645.  
  646.    if (vflag || dflag)
  647.       fprintf(stderr, "Using quotafile %s\n", quotafile);
  648.  
  649.    if (quotactl(QCMD(Q_GETQUOTA, type), fsname, 0, (caddr_t)&dq_dqb) == 0)
  650.       quota_enabled = 1;
  651.  
  652.    if ((vflag || dflag) && quota_enabled)
  653.       fprintf(stderr, "Updating in-core %s quotas\n", quotatypes[type]);
  654.  
  655.    if ((fd = open(quotafile, O_RDWR | O_CREAT, 0600)) < 0)
  656.       abort_now("open", "dump_to_file(%s): ", quotafile);
  657.  
  658.    if (flock(fd, LOCK_EX) < 0)
  659.       abort_now("flock", "dump_to_file(%s): ", quotafile);
  660.  
  661.    /*
  662.     * First dump the gracetimes that are always a first in the 
  663.     * quotafile. Only dump new gracetimes when creating a new 
  664.     * quotafile.
  665.     */
  666.    
  667.    if (read(fd, &dq_dqb, sizeof(struct dqblk)) <= 0) {
  668.       memset((caddr_t *)&dq_dqb, 0, sizeof(struct dqblk));
  669.       dq_dqb.dqb_btime = MAX_DQ_TIME;
  670.       dq_dqb.dqb_itime = MAX_IQ_TIME;
  671.       write(fd, &dq_dqb, sizeof(struct dqblk));
  672.    }
  673.  
  674.    max_id = highestid[type];
  675.    while (id <= max_id) {
  676.       if (lseek(fd, dqoff(id), SEEK_SET))
  677.          read(fd, &dq_dqb, sizeof(struct dqblk));
  678.       if ((dquot = lookup_dquot(id, type)) != NODQUOT) {
  679.          dq_curinodes = dquot->dq_curinodes;
  680.          dq_curblocks = dquot->dq_curblocks;
  681.          if (dflag)
  682.             fprintf(stderr, "%s %d: curinodes: %d curblocks: %d\n",
  683.                     quotatypes[type], id, dq_curinodes, dq_curblocks);
  684.          add_dlinks(&dq_curinodes, &dq_curblocks, id, type);
  685.          if (dflag)
  686.             fprintf(stderr, "%s %d: curinodes: %d curblocks: %d\n",
  687.                     quotatypes[type], id, dq_curinodes, dq_curblocks);
  688.       } else
  689.          memset((caddr_t *)&dq_dqb, 0, sizeof(struct dqblk));
  690.  
  691.       /*
  692.        * If the quota is updated with the systemcall it isn't needed to update
  693.        * it in the file. Because the kernel will do that with the next sync.
  694.        */
  695.       if (quota_enabled)
  696.          if (quotactl(QCMD(Q_SETUSE, type), fsname, id, (caddr_t)&dq_dqb) == 0) {
  697.             id++;
  698.             continue;
  699.          }
  700.  
  701.       if (lseek(fd, dqoff(id), SEEK_SET))
  702.          write(fd, &dq_dqb, sizeof(struct dqblk));
  703.       id++;
  704.    }
  705.    flock(fd, LOCK_UN);
  706.    close(fd);
  707. }
  708.  
  709. /*
  710.  * Add a number of blocks and inodes to a quota.
  711.  */
  712. void add_to_quota_ext2(int id, long blocks, int type)
  713. {
  714.    int wanted;
  715.    struct dquot *lptr;
  716.  
  717.    if ((lptr = lookup_dquot(id, type)) == NODQUOT)
  718.       if ((lptr = add_dquot(id, type)) == NODQUOT)
  719.      abort_now("add_to_quota", "Can't add dquot structure type %s for uid %d\n",
  720.            quotatypes[type], id);
  721.    lptr->dq_curinodes++;
  722.    lptr->dq_curblocks += blocks/2;    /* Dunno why /2 but otherwise everthing is wrong */
  723. }
  724.  
  725.